package com.huarui.quotation.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.ewaf.framework.exception.BizException;
import org.ewaf.framework.service.BaseService;
import org.ewaf.framework.struts2.util.DateFormatUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import com.huarui.company.dao.ICompanyDao;
import com.huarui.company.model.Company;
import com.huarui.companyconfig.dao.ICompanyConfigDao;
import com.huarui.companyconfig.model.CompanyConfig;
import com.huarui.inventory.dao.IInventoryDao;
import com.huarui.inventory.model.Inventory;
import com.huarui.market.dao.IMarketDao;
import com.huarui.market.model.Market;
import com.huarui.part.dao.ICarModelDao;
import com.huarui.part.dao.IPartCategoryDao;
import com.huarui.part.dao.IPartPropertyDao;
import com.huarui.part.error.PartPropertyErrorEnum;
import com.huarui.part.model.CarModel;
import com.huarui.part.model.PartCategory;
import com.huarui.part.model.PartProperty;
import com.huarui.quotation.dao.IQuotationDao;
import com.huarui.quotation.model.Quotation;
import com.huarui.user.model.SessionMessage;
import com.huarui.user.security.UserHolder;
import com.huarui.util.ConstantUtil;

/**
 * 报价表业务逻辑
 * 
 * @author ycf
 * 
 */
public class QuotationService extends BaseService {
	private static final Logger log = Logger.getLogger(QuotationService.class);

	private IQuotationDao getDao() {
		return (IQuotationDao) dao;
	}

	private ICarModelDao carModelDao;
	private IPartCategoryDao partCategoryDao;
	private IInventoryDao inventoryDao;
	private IPartPropertyDao partPropertyDao;
	private ICompanyDao companyDao;
	private IMarketDao marketDao;
	private ICompanyConfigDao companyConfigDao;
	public List<CarModel> getAllCarModels() {
		return carModelDao.searchCarModels(null);
	}

	public List<PartCategory> getFirstLevel() {
		return partCategoryDao.getFirstLevel();
	}

	public List<PartCategory> getSubLevel(Integer level1Id) {
		return partCategoryDao.getSubLevel(level1Id);
	}

	public void setPartCategoryDao(IPartCategoryDao partCategoryDao) {
		this.partCategoryDao = partCategoryDao;
	}

	public void setInventoryDao(IInventoryDao inventoryDao) {
		this.inventoryDao = inventoryDao;
	}

	public List<Map<String, String>> getQuotationsByName(Integer source,
			String name) {
		return getDao().getQuotationsByName(source, name);
	}

	public List<Map<String, String>> getQuotationsByCode(Integer source,
			String code) {
		return getDao().getQuotationsByCode(source, code);
	}

	public List<Map<String, String>> getQuotationsByComplexCond(
			Map<String, String> map) {
		return getDao().getQuotationsByComplexCond(map);
	}

//	public Map<String, Object> getQuotationListByComplex(Map<String, Object> map) {
//		
//		Integer totalProperty = this.getDao().getQuotaCountInfo(map);
//		List<Map<String, Object>> list = this.getDao()
//				.getQuotationListByComplex(map);
//
//		map.clear();
//		map.put("totalProperty", totalProperty);
//		map.put("root", list);
//		
//		return map;
//	}

	/**
	 * documentType:0表示入库的时候,1表示销售的时候
	 * 
	 * @param documentType
	 */

	public void modifyQuotation(Quotation quotation, Integer documentType) {

		if (documentType == 0) {

			if (quotation.getGmtLastSold() == null) {

				Date date = DateFormatUtil.parseDate("2000-01-01");

				// java.sql.Date data=new java.sql.Date(dateParam.getTime());

				quotation.setGmtLastSold(date);
			}

			this.getDao().update(quotation);

		} else {

			// Date date = new java.sql.Date(dateParam.getTime());

			quotation.setGmtLastSold(new Date());

			this.getDao().update(quotation);
		}

	}

	/**
	 * xzz
	 * 
	 * @param inventoryList
	 */
	public void updateAll(final List<Inventory> inventoryList) {
		final SessionMessage sessionMessage = UserHolder
				.getCurrentSessionMessage();
		transactionTemplate.execute(new TransactionCallback() {
			@SuppressWarnings("unused")
			@Override
			public Object doInTransaction(TransactionStatus status) {
				List<Inventory> list=updateInventoryList(inventoryList);
				boolean isInsert=insertListQuotation();//当quatation表中没有任何该公司的记录。就将inventory表的数据插入qutation
				List<Quotation> quotationList = new ArrayList<Quotation>();
				try {
					Company company = (Company) companyDao.getById(sessionMessage.getCompanyId());
					Market market = marketDao.getMarketByCompanyId(company.getId());
					for (Inventory inventory : list) {
						if(inventory.getPublicanLevel().equals(Inventory.publicanLevel_ALL)||inventory.getPublicanLevel().equals(Inventory.publicanLevel_PARTNER)){
							Quotation quotation = (Quotation) dao.getById(inventory.getId());
							if(quotation==null){
								Inventory tempInv=(Inventory) inventoryDao.getById(inventory.getId());
								Quotation quota=copyToQuotation(tempInv);
								getDao().createPassPermission(quota, sessionMessage.getCompanyId());
							}else{
								quotation.setRetailPrice(inventory.getRetailPrice());
								quotation.setInsurancePrice(inventory.getInsurancePrice());
								quotation.setPublicanLevel(inventory.getPublicanLevel());
								getDao().update(quotation);
							}
						}else if(inventory.getPublicanLevel().equals(Inventory.publicanLevel_PRIVATE)){
							getDao().deleteById(inventory.getId());
						}
					

					}

					getDao().bacthUpdatQuotation(quotationList,company.getId());
				} catch (Exception e) {
					log.error("更新报价失败......", e);
					throw new RuntimeException(e);
				}
				return null;
			}
		});

	}
	private List<Inventory> updateInventoryList(List<Inventory> inventoryList){
		List<Inventory> resultList=new ArrayList<Inventory>();
		for(Inventory inventory:inventoryList){
			Inventory newInv=(Inventory) inventoryDao.getById(inventory.getId());
			newInv.setRetailPrice(inventory.getRetailPrice());
			newInv.setInsurancePrice(inventory.getInsurancePrice());
			newInv.setPublicanLevel(inventory.getPublicanLevel());
			inventoryDao.update(newInv);
			resultList.add(newInv);
		}
		return resultList;
	}
	private boolean insertListQuotation(){
		SessionMessage sm=UserHolder.getCurrentSessionMessage();
		Map<String,Object> paramsMap=new HashMap<String, Object>();
		paramsMap.put("companyId", sm.getCompanyId());
		Integer count=getDao().searchQuotationCountByComplex(paramsMap);
		if(count==null||count==0){
			List<String> publicanLevelList=new ArrayList<String>();
			publicanLevelList.add(Inventory.publicanLevel_ALL);
			publicanLevelList.add(Inventory.publicanLevel_PARTNER);
			paramsMap.put("publicanLevelList",publicanLevelList);
			List<Inventory> list=inventoryDao.getInventoryByConditions(paramsMap);
			/*paramsMap.put("inventoryList", list);
			List<PartProperty> partproList=partPropertyDao.getPartAndPartPropertyByCondition(paramsMap);
			for(PartProperty)*/
			List<Quotation> quoList=new ArrayList<Quotation>();
			for(Inventory inventory:list){
				Quotation quotation=copyToQuotation(inventory);
				quoList.add(quotation);
			}
			getDao().batchInsertQuotation(quoList,sm.getCompanyId());
			return true;
		}
		return false;
	}
	private Quotation copyToQuotation(Inventory inventory){
		
		Quotation quotation=new Quotation();
		quotation.setId(inventory.getId());
		quotation.setPartId(inventory.getPartId());
		quotation.setCode(inventory.getCode());
		quotation.setSource(inventory.getSource());
		quotation.setName(inventory.getName());
		quotation.setNameEn(inventory.getNameEn());
		quotation.setPyCode(inventory.getPyCode());
		quotation.setMeasurementUnit(inventory.getMeasurementUnit());
		//quotation.setSwapCode(inventory.getSwapCode());
		quotation.setPartCategoryId(inventory.getPartCategoryId());
		quotation.setLevel1Name(inventory.getLevel1Name());
		quotation.setLevel2Name(inventory.getLevel2Name());
		quotation.setLevel1Id(inventory.getLevel1Id());
		quotation.setBrand(inventory.getBrand());
		quotation.setOrigin(inventory.getOrigin());
		quotation.setOnHand(inventory.getOnHand());
		quotation.setRetailPrice(inventory.getRetailPrice());
		quotation.setPublicanLevel(inventory.getPublicanLevel());
		quotation.setGmtCreate(new Date());
		quotation.setGmtModify(new Date());
		quotation.setTmsVersion(new Date());
		return quotation;
	}
	public boolean batchOperationQuotation(List<PartProperty> insertList,List<PartProperty> updateList){
		insertList.addAll(updateList);
		return batchOperationQuotation(insertList);
	}
	private CompanyConfig getCompanyConfig(Integer companyId,String varName){
		Map<String,Object> map=new HashMap<String, Object>();
		map.clear();
		map.put("companyId", companyId);
		List<CompanyConfig> list=companyConfigDao.getListByConditions(map);
		for(CompanyConfig companyConfig:list){
			if(companyConfig.getVarName().equals(varName)){
				return companyConfig;
			}
		}
		return null;
	}
	public boolean batchOperationQuotation(final Integer companyId){
		try {
			transactionTemplate.execute(new TransactionCallback() {
				
				@Override
				public Object doInTransaction(TransactionStatus status) {
					Map<String,Object> map=new HashMap<String, Object>();
					map.put("companyId", companyId);
					map.put("isLock", true);
					List<PartProperty> list=partPropertyDao.getListByCondition(map);
					batchOperationQuotation(list);
					return null;
				}
			});
		} catch (Exception e) {
			log.error("购买套餐更新报价表失败",e);
			return false;
		}
		return true;
	}
	public boolean batchOperationQuotation(List<PartProperty> list){
		SessionMessage sm=UserHolder.getCurrentSessionMessage();
		CompanyConfig companyConfig=getCompanyConfig(sm.getCompanyId(), "publicanLevel");
		List<PartProperty> insertList=new ArrayList<PartProperty>();
		List<PartProperty> updateList=new ArrayList<PartProperty>();
		List<Quotation> insQuoList=new ArrayList<Quotation>();
		List<Quotation> updQuoList=new ArrayList<Quotation>();
		List<Quotation> delQuoList=new ArrayList<Quotation>();
		for(PartProperty partProperty:list){
			if(partProperty.getId()==null){
				partProperty.setPublicanLevel(companyConfig!=null?companyConfig.getVarValue():"1");
				if(partProperty.getQuotationQty()==null)partProperty.setQuotationQty(PartProperty.QUOTATIONQTY_MIN);
				partPropertyDao.create(partProperty);
				insertList.add(partProperty);
			}else{
				updateList.add(partProperty);
			}
		}
		lockPartPropety(updateList);
		List<Quotation> databaseQuoList=lockQuotationByCompanyId(sm.getCompanyId(), updateList);
		Map<Integer,Quotation> quotationMap=new HashMap<Integer, Quotation>();
		for(Quotation quotation:databaseQuoList){
			quotationMap.put(quotation.getId(), quotation);
		}
		for(PartProperty partProperty:insertList){
			if(validateInsertQuotation(partProperty)){//通过4个条件验证
				Quotation quotation=createQuotation(partProperty);
				insQuoList.add(quotation);
			}
		}
		for(PartProperty partProperty:updateList){
			Quotation quotation=quotationMap.get(partProperty.getId());
			if(!validateInsertQuotation(partProperty)){
				if(quotation!=null){
					delQuoList.add(quotation);
				}
			}else{
				if(quotation!=null){
					quotation=updateQuotation(partProperty, quotation);
					updQuoList.add(quotation);
				}else{
					quotation=createQuotation(partProperty);
					insQuoList.add(quotation);
				}
			}
		}
		if(validatePay(sm.getCompanyId())){//验证是否有插入quotation表的权限
			getDao().batchInsertQuotation(insQuoList, sm.getCompanyId());
			getDao().bacthUpdatQuotation(updQuoList, sm.getCompanyId());
			getDao().batchDeleteQuotation(delQuoList);
		}
		partPropertyDao.batchUpdatePartProperty(updateList);
		return true;
	}
	private void lockPartPropety(List<PartProperty> updateList) {
		Map<String,Object> map=new HashMap<String, Object>();
		map.put("isLock", true);
		map.put("partPropertyList", updateList);
		partPropertyDao.getPartAndPartPropertyByCondition(map);
	}

	private Quotation updateQuotation(PartProperty partProperty,Quotation quotation){
		quotation.setOnHand(partProperty.getOnHand());
		quotation.setRetailPrice(partProperty.getRetailPrice());
		quotation.setInsurancePrice(partProperty.getInsurancePrice());
		quotation.setPublicanLevel(partProperty.getPublicanLevel());
		quotation.setQuotationQty(partProperty.getQuotationQty());
		return quotation;
		
	}
	private Quotation createQuotation(PartProperty partProperty){
		Quotation quotation=new Quotation();
		quotation.setId(partProperty.getId());
		quotation.setPartId(partProperty.getPartId());
		quotation.setCode(partProperty.getCode());
		quotation.setSource(partProperty.getSource());
		quotation.setName(partProperty.getName());
		quotation.setNameEn(partProperty.getNameEn());
		quotation.setPyCode(partProperty.getPyCode());
		quotation.setMeasurementUnit(partProperty.getMeasurementUnit());
		quotation.setSwapCode(partProperty.getSwapCode());
		quotation.setPartCategoryId(partProperty.getPartCategoryId());
		quotation.setLevel1Name(partProperty.getLevel1Name());
		quotation.setLevel2Name(partProperty.getLevel2Name());
		quotation.setLevel1Id(partProperty.getLevel1Id());
		quotation.setBrand(partProperty.getBrand());
		quotation.setOrigin(partProperty.getOrigin());
		quotation.setOnHand(partProperty.getOnHand());
		quotation.setRetailPrice(partProperty.getRetailPrice());
		quotation.setInsurancePrice(partProperty.getInsurancePrice());
		quotation.setPublicanLevel(partProperty.getPublicanLevel());
		quotation.setCarModel(partProperty.getCarModel());
		return quotation;
	}
	
	private boolean validateInsertQuotation(PartProperty partProperty){
		if(		//publicanLevel=2 不公开 的记录
				partProperty.getPublicanLevel().equals(PartProperty.PUBLICANLEVEL_NOPUBLIC)||
				//库存数量为0
				!(partProperty.getOnHand()!=null&&partProperty.getOnHand()>=1)||
				//报价数量大于20，或者报价数量小于1
				!(partProperty.getQuotationQty()!=null&&partProperty.getQuotationQty()>=PartProperty.QUOTATIONQTY_MIN&&partProperty.getQuotationQty()<=PartProperty.QUOTATIONQTY_MAX)){
			
			return false;
		}else{
			partProperty.setGmtLastType(PartProperty.GMTLASTTYPE_QUOTATION);
			return true;
		}
	}
	private List<Quotation> lockQuotationByCompanyId(Integer companyId,List<PartProperty> list){
		Map<String,Object> map=new HashMap<String, Object>();
		map.put("companyId", companyId);
		map.put("isLock", true);
		map.put("partPropertyList", list);
		List<Quotation> retList=getDao().getListByConditions(map);
		return retList;
	}
	
	
	public void handlePartPropertyAndQuotation(List<Inventory> inventories,boolean isAdd) {
		List<PartProperty> addPartProperties = new ArrayList<PartProperty>();//partproperty表不存在记录
		List<PartProperty> modifyPartProperties = new ArrayList<PartProperty>();//partproperty表已存在记录
		List<PartProperty> partProperties = new ArrayList<PartProperty>();
		Map<Integer,PartProperty> mapPartProperty = new HashMap<Integer, PartProperty>();
		SessionMessage sessionMessage = UserHolder.getCurrentSessionMessage();
		if(!inventories.isEmpty()){
			Map<String, Object> map =new HashMap<String, Object>();
			map.put(ConstantUtil.PARAM_OF_COMPANYID, sessionMessage.getCompanyId());
			map.put(ConstantUtil.PARAM_OF_ITEMLIST, inventories);
			map.put(ConstantUtil.UPDATE, true);
			//根据入库明细查找所有partproterty表已存在记录
			partProperties = partPropertyDao.getPartPropertyListByConditions(map);
			for(PartProperty partProperty : partProperties){
				mapPartProperty.put(partProperty.getPartId(), partProperty);
			}
			for(Inventory inventory : inventories){
				PartProperty partProperty = mapPartProperty.get(inventory.getPartId());
				if(partProperty == null){
				    // 零件属性表不存在，则创建此零件信息
				    partProperty = new PartProperty();
				    BeanUtils.copyProperties(inventory, partProperty, new String[]{"id"});
				    addPartProperties.add(partProperty);
				}else{
				    // 零件属性表存在此零件信息,则更改库存，成本
					BigDecimal partPropertyTotalCost = partProperty.getCost().multiply(new BigDecimal(partProperty.getOnHand()));
					BigDecimal changeItemTotalCost = inventory.getCost().multiply(new BigDecimal(inventory.getChangeQuantity()));
					BigDecimal cost;
					Integer totalQuantity;
					if(isAdd){	
						//采购入库
						BigDecimal totalCost = partPropertyTotalCost.add(changeItemTotalCost);
						totalQuantity = partProperty.getOnHand() + inventory.getOnHand();
						if(totalQuantity.equals(0)){
							cost = partProperty.getCost();
						}else{
							cost = totalCost.divide(new BigDecimal(totalQuantity),4,BigDecimal.ROUND_HALF_UP);
						}						
					}else{
						//销售出库
						totalQuantity = partProperty.getOnHand() - inventory.getChangeQuantity();
						cost = partProperty.getCost();
					}
					//四舍五入,保留四位小数
					partProperty.setCost(cost);
					partProperty.setOnHand(totalQuantity);
					partProperty.setGmtLastSold(inventory.getGmtLastSold());
					partProperty.setGmtLastType(inventory.getGmtLastType());
					modifyPartProperties.add(partProperty);
				}				
			}
		}
		batchOperationQuotation(addPartProperties, modifyPartProperties);
	}

	private boolean validatePay(Integer companyId){
		return getDao().validateInsertPermisstion(companyId);
	}
	public void setCompanyDao(ICompanyDao companyDao) {
		this.companyDao = companyDao;
	}

	public void setMarketDao(IMarketDao marketDao) {
		this.marketDao = marketDao;
	}

	public void setCarModelDao(ICarModelDao carModelDao) {
		this.carModelDao = carModelDao;
	}

	public void setPartPropertyDao(IPartPropertyDao partPropertyDao) {
		this.partPropertyDao = partPropertyDao;
	}

	public void handlePartPropertyAndQuotationForReturn(List<Inventory> inventories,boolean isSaleReturn) {
		List<PartProperty> partProperties = new ArrayList<PartProperty>();
		if (!inventories.isEmpty()) {
			for (Inventory inventory : inventories) {
				SessionMessage sm = UserHolder.getCurrentSessionMessage();
				PartProperty partProperty = partPropertyDao.getPartPropertyByPartId(inventory.getPartId(), sm.getCompanyId(), true);
				//原数量
				Integer previousOnHand = partProperty.getOnHand();
				//原成本价
				BigDecimal previousCost = partProperty.getCost();					
				//退货成本价
				BigDecimal cost = inventory.getCost();
				//退货数量
	        	Integer returnQuantity = inventory.getChangeQuantity();
				//原总成本
				BigDecimal preTotalCost = previousCost.multiply(new BigDecimal(previousOnHand));
				//退货总成本
				BigDecimal returnCost = cost.multiply(new BigDecimal(returnQuantity));
				//剩余数量				
				Integer onHand;
				//退货后总成本
				//BigDecimal nowTotalCost;
				//退货后成本
				BigDecimal newCost;
				if(isSaleReturn){
					//销售退库,修改数量和成本，零件属性表里的成本=（原数量*原成本价+退货数量*入库成本价）/(原数量+退货数量)
					onHand = previousOnHand + returnQuantity;
					 //退货后总成本
		            //nowTotalCost = preTotalCost.add(returnCost);
					newCost = previousCost;
				}else{
					//采购退库,修改数量和成本，零件属性表里的成本=（原数量*原成本价-退货数量*入库成本价）/(原数量-退货数量)
					onHand = previousOnHand - returnQuantity;
					//退货后总成本
					BigDecimal nowTotalCost = preTotalCost.subtract(returnCost);
					
					newCost = onHand.equals(0)? previousCost : nowTotalCost.divide(new BigDecimal(onHand), 4, BigDecimal.ROUND_HALF_UP);
				}				
				if (onHand < 0) {
					throw new BizException(PartPropertyErrorEnum.PARTPROPERTY_ONHAND_ERROR);
				}												
				partProperty.setOnHand(onHand);
				partProperty.setCost(newCost);
				partProperties.add(partProperty);
			}
		}
		batchOperationQuotation(partProperties);
	}

	public void setCompanyConfigDao(ICompanyConfigDao companyConfigDao) {
		this.companyConfigDao = companyConfigDao;
	}

}
